package com.hr.config;

import com.hr.shiro.cache.RedisCache;
import com.hr.shiro.cache.RedisCacheManager;
import com.hr.shiro.cache.RedisSessionDAO;
import com.hr.shiro.realm.SimpleRealm;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * Shiro配置
 */
@Configuration
public class ShiroConfig {

    /**
     * 开启对shiro注解的支持
     * @param sessionsSecurityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SessionsSecurityManager sessionsSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(sessionsSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 开启aop注解支持
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * Shiro 过滤器链条，将此过滤器链条 注入spring ioc容器中
     * @return
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        //过滤器链条
        DefaultShiroFilterChainDefinition filterChain
                = new DefaultShiroFilterChainDefinition();
        /**
         * anon: 开放路径，允许匿名访问，不需要权限和不需要登录就可以访问
         */
        //登录相关的接口不要拦截
        filterChain.addPathDefinition("/login", "anon");
        filterChain.addPathDefinition("/aoaUser/queryByUserName", "anon");
//        filterChain.addPathDefinition("/aoaSysMenu/queryListByRoleId", "anon");
        //由网关路由api-ui 不做拦截
        filterChain.addPathDefinition("/api-ui/**", "anon");
        //静态资源不要拦截
        filterChain.addPathDefinition("/static/**", "anon");
        //静态页面不要拦截
        filterChain.addPathDefinition("/templates/**", "anon");

        //走 thymeleaf
//      filterChain.addPathDefinition("/page/**", "anon");

        //swagger 资源不要拦截
        filterChain.addPathDefinition("/swagger-ui.html*", "anon");
        filterChain.addPathDefinition("/swagger-resources/**", "anon");
        filterChain.addPathDefinition("/v2/**", "anon");
        filterChain.addPathDefinition("/webjars/**", "anon");

        /**
         * authc:需要登录后才可以访问路径,
         * 我这里配置 /** 表示除上面的路径之外，其他任何路径都需要经过身份认证才能访问
         */
        filterChain.addPathDefinition("/**", "authc");
        return filterChain;
    }

    /**
     * 配置自定义 Realm(数据安全域)
     * 当Shiro进行身份认证或授权访问时都需要用到Realm,一般情况下每一类资源对应一个Realm。
     * Shiro框架要求至少要配置一个Realm
     * @return
     */
    @Bean
    public Realm sampleRealm(){
        //我们自定义 Realm(数据安全域)
        SimpleRealm simpleRealm = new SimpleRealm();
        return simpleRealm;
    }

    /**
     * ************************************************
     * shiro + redis 配置 start
     */
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    /**
     * ioc容器中注入 基于shiro 的操作缓存库的 java 类
     * @return
     */
    @Bean
    public RedisCache redisCache(){
        return new RedisCache(redisTemplate);
    }
    /**
     * 往ioc容器中注入  基于shiro 实现的 redis缓存管理器
     * @return
     */
    @Bean
    public RedisCacheManager redisCacheManager(){
        //我们手动创建它
        RedisCacheManager redisCacheManager =
                new RedisCacheManager(redisCache());
        return redisCacheManager;
    }

    /**
     * 我们自己实现的session CRUD
     * @return
     */
    @Bean
    public RedisSessionDAO redisSessionDAO(){
        return new RedisSessionDAO(redisTemplate);
    }
    /**
     * 我们自己创建一个 session管理器
     * @return
     */
    @Bean
    public DefaultWebSessionManager defaultWebSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //针对session 增、删、改、查的dao类，我们自己实现
        sessionManager.setSessionDAO(redisSessionDAO());

        return sessionManager;
    }

    /**
     * 往ioc容器中注入 安全访问控制管理器 对象
     * @return
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        //我们自己创建一个 安全访问控制管理器 对象
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置数据安全域,不用担心会产生多例，spring会做处理
        securityManager.setRealm(sampleRealm());


//        //将安全管理器绑定到线程中(好像没卵用)
//        ThreadContext.bind(securityManager);



        //设置缓存管理器(此缓存用于存储权限信息)
        securityManager.setCacheManager(redisCacheManager());
        /**
         * 我们的shiro要支持分布式，我们决定将session存储到redis中
         * 但是，shiro默认将session存储到servlet context中.
         * 我们要换掉它
         */
        securityManager.setSessionManager(defaultWebSessionManager());

        return securityManager;
    }


    /**
     * shiro + redis 配置 end
     * ************************************************
     */
}

